#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<semaphore.h>

#include "cJSON.h"
#include "queue.h"

//显示菜单
void display_menu(void);
//创建套接字
int create_sock(const char *ip, unsigned short port);
//解析处理函数
void parsing_processing(const char *type, const char *username, const char *password, int sock);

int main(int argc, const char *argv[]){
	int choice = 0;
	int retval = 0;
	char type[20] = {0};
	char username[20] = {0};
	char password[20] = {0};
	
	while(1)
	{
		//调用显示菜单函数
		display_menu();
		printf("请输入您要办理的业务：\n");
		scanf("%d", &choice);
		switch(choice)
		{
			case 1:
			{
				//调用创建套接字函数
				int sock = create_sock("127.0.0.1", 6868);
				strcpy(type, "register");
				printf("请输入您的用户名：\n");
				scanf("%s", username);
				printf("请输入您的密码：\n");
				scanf("%s", password);
				//调用解析处理函数
				parsing_processing(type, username, password, sock);	
			}
				break;
			case 2:
			{
				//调用创建套接字函数
				int sock = create_sock("127.0.0.1", 6868);
				strcpy(type, "login");
				printf("请输入您的用户名：\n");
				scanf("%s", username);
				printf("请输入您的密码：\n");
				scanf("%s", password);
				//调用解析处理函数
				parsing_processing(type, username, password, sock);
			}
				break;
			case 3:
			{
				//调用创建套接字函数
				int sock = create_sock("127.0.0.1", 6868);
				strcpy(type, "change");
				printf("请输入您的用户名：\n");
				scanf("%s", username);
				printf("请输入您的新密码：\n");
				scanf("%s", password);
				//调用解析处理函数
				parsing_processing(type, username, password, sock);		
			}
				break;	
			case 4:
				printf("已成功退出系统！\n");
				return 0;
			default :
				printf("输入错误！\n");
				break;
		}
	}
	
	return 0;
}

//显示菜单
void display_menu(void)
{
	printf("*****************欢迎使用微控智慧能源管理系统******************\n");
	printf("*************************[1] 注册**************************\n");
	printf("*************************[2] 登录**************************\n");
	printf("*************************[3] 修改密码***********************\n");
	printf("*************************[4] 退出**************************\n");
}

//创建套接字
int create_sock(const char *ip, unsigned short port)
{
	int sock = 0;
	int retval = 0;
	//功能：创建套接字
	//函数原型: int socket(int domain, int type, int protocol);
	//函数参数：1.domain：即协议域，又称为协议族（family）。常用的协议族有，AF_INET、AF_INET6、AF_LOCAL（或称AF_UNIX，Unix域socket）、AF_ROUTE等等。
	//2.types: 套接字类型   TCP/IP的socket提供下列三种类型套接字。
	//流式套接字（SOCK_STREAM）：需要双方建立可行的数据连接后才能通信。 
	//数据报式套接字（SOCK_DGRAM）：只是简单地将数据发送到对应的目的主机即可，而不管对方是否处于存活状态，对方是否允许以及该数据包是否完整地被发送到目标主机。
	//原始式套接字（SOCK_RAW）：该接口允许对较低层协议，如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。 
	//3.protocol：指定应用程序所使用的通信协议，在Internet通讯域中，此参数一般取值为0。
	sock = socket(AF_INET, SOCK_STREAM, 0);
	//成功：返回新创建套接字描述符；失败：返回-1
	if(sock == -1)
	{
		perror("socket");  //套接字创建失败
		exit(-1);
	}
	
	struct sockaddr_in seraddr;
	memset(&seraddr, 0, sizeof(struct sockaddr_in));
	
	seraddr.sin_family = AF_INET;  //协议族
	//htons: 转化为其它编程语言可以理解的
	seraddr.sin_port = htons(port);  //端口
	seraddr.sin_addr.s_addr = inet_addr(ip);  //ip地址
	
	//功能：客户端通过调用connect函数来建立与TCP服务器连接
	//1.sockfd: 客户端的socket描述符
	//2.addr: 服务器的socket地址
	//3.addrlen: socket地址的长度
	retval = connect(sock, (struct sockaddr *)&seraddr, sizeof(struct sockaddr_in));
	//成功：返回0，失败：返回-1
	if(retval == -1)
	{
		perror("connect");  //连接失败
		close(sock);  //关闭套接字
		exit(-1);
	}
	
	return sock;
}

//解析处理函数
void parsing_processing(const char *type, const char *username, const char *password, int sock)
{	

	int retval = 0;
	
						//组包
	cJSON *json = NULL;
	char *dest = NULL;
	//定义json类型指针并初始化
	json = cJSON_CreateObject();
	//给json对象增加"键-值"对
								 //键     //将值转化为json类型格式
	cJSON_AddItemToObject(json, "type", cJSON_CreateString(type));
	cJSON_AddItemToObject(json, "username", cJSON_CreateString(username));
	cJSON_AddItemToObject(json, "password", cJSON_CreateString(password));
	
	//将json对象转化为标准的c格式字符串
	dest = cJSON_Print(json);
	
	//功能：向一个已连接的socket发送数据
	//1.sockfd: 一个已连接套接字的描述符
	//2.buf: 是指定的缓冲区，即指针，指向一个内存单元，包含待发送的数据
	//3.len: 是要发送数据的长度
	//4.flag: 调用执行方式，一般为0
	retval = send(sock, dest, strlen(dest), 0);
	//成功：返回所发送数据的总数，失败：返回-1
	if(retval == -1)
	{
		perror("send");  //发送失败								
		close(sock);   //关闭套接字
		exit(-1);
	}
	
	//释放空间
	free(dest);
	cJSON_Delete(json);
	
	char buf[100] = {0};
	//功能：从一个已连接的socket接收数据
	//1.fd: 是一个已连接套接字的描述符
	//2.buf: 指定的缓冲区，用于存放接收到的数据
	//3.len: 要接收数据的长度
	//4.flags: 调用执行方式，一般为0
	retval = recv(sock, buf, sizeof(buf) - 1, 0);
	//成功：返回所接收数据的总数，失败：返回-1
	if(retval == -1)
	{
		perror("recv");  //接收失败
		close(sock);   //关闭套接字
		exit(-1);
	}
	
	char result[20] = {0};
	
						//解包
						
	//由json格式字符串产生一个json对象										
	json = cJSON_Parse(buf);
	cJSON *node = NULL;
	//由键获取值
	node = cJSON_GetObjectItem(json, "result");
	if(node == NULL)
	{
		printf("can't find\n");
		exit(-1);
	}
	if(node -> type == cJSON_String)
	{
		strcpy(result, node -> valuestring);
	}
	
	printf("%s\n", result);
	
	//释放空间
	cJSON_Delete(json);
	
	//关闭套接字
	close(sock);	
}
	
	
	
	
